package cm.utils;

import cn.hutool.poi.excel.ExcelWriter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author yxh
 * @Description: Excel导出工具
 * @Date: Created in 2022/8/18 10:29
 * @Modified By:
 */
@Slf4j
public class ExcelUtil {

    public static void exportExcel(HttpServletResponse response, String fileName, List<List<?>> table, String titleName, boolean passCurrentRow, boolean isXlsx, boolean autoSizeColumn) {
        if (table == null || table.isEmpty() || table.get(0) == null) {
            return;
        }
        ExcelWriter writer = new ExcelWriter(isXlsx);
        //跳过首行
        if (passCurrentRow) {
            writer.passCurrentRow();
        }
        //合并单元格后标题行
        if (StringUtils.isNoneBlank(titleName)) {
            writer.merge(table.get(0).size() - 1, titleName);
        }
        writer.write(table, true);
        if (autoSizeColumn) {
            autoSizeColumnAll(writer);
        }
        String contentType = writer.isXlsx() ? "XLSX" : "XLS";
        DownloadResponseUtil.responseSetProperties(fileName, writer, response, contentType);
    }

    public static <T> void exportExcel(HttpServletResponse response, String fileName, List<T> rows, Map<String, String> colMap,
                                       String titleName, boolean passCurrentRow, boolean isXlsx, boolean autoSizeColumn) {
        if (rows == null) {
            return;
        }
        ExcelWriter writer = new ExcelWriter(isXlsx);
        if (CollectionUtils.isEmpty(rows)) {
            List<List<?>> table = new ArrayList();
            List<String> header = new ArrayList<>(colMap.values());
            table.add(header);
            exportExcel(response, fileName, table, titleName, passCurrentRow, isXlsx, autoSizeColumn);
            return;
        }
        //跳过首行
        if (passCurrentRow) {
            writer.passCurrentRow();
        }
        writer.setOnlyAlias(true);
//        for (String key : colMap.keySet()) {
//            writer.addHeaderAlias(key, colMap.get(key));
//        }
        writer.setHeaderAlias(colMap);
        //合并单元格-标题行
        if (StringUtils.isNoneBlank(titleName)) {
            writer.merge(colMap.size() - 1, titleName);
        }
        writer.write(rows, true);

        if (autoSizeColumn) {
            autoSizeColumnAll(writer);
        }
//        byte[] bytes = getBytes(writer);
        String contentType = writer.isXlsx() ? "XLSX" : "XLS";
        DownloadResponseUtil.responseSetProperties(fileName, writer, response, contentType);
    }

    public static byte[] getBytes() {
        byte[] bytes = new byte[0];
        ByteArrayOutputStream byteArrayOutputStream = null;
        OutputStreamWriter outputStreamWriter = null;
        BufferedWriter bufferedWriter = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            outputStreamWriter = new OutputStreamWriter(byteArrayOutputStream, StandardCharsets.UTF_8);
            bufferedWriter = new BufferedWriter(outputStreamWriter);
            //excel文件需要通过文件头的bom来识别编码，而CSV文件格式不自带bom,所以写文件时，需要先写入bom头，否则excel打开乱码
            bufferedWriter.write(new String(ByteOrderMark.UTF_8.getBytes()));
            //写入文件数据

            bufferedWriter.write("");
            bufferedWriter.flush();
            bytes = byteArrayOutputStream.toString(StandardCharsets.UTF_8.name()).getBytes();
        } catch (Exception e) {
            log.error("iostream error:{}", e.getMessage(), e);
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                }
                if (outputStreamWriter != null) {
                    outputStreamWriter.close();
                }
                if (byteArrayOutputStream != null) {
                    byteArrayOutputStream.close();
                }
            } catch (IOException e) {
                log.error("iostream close IOException:{}", e.getMessage(), e);
            }
        }
        return bytes;
    }


    public static void autoSizeColumnAll(ExcelWriter writer) {
        Sheet sheet = writer.getSheet();
        if (sheet.getLastRowNum() > 0) {
            short lastCellNum = sheet.getRow(sheet.getLastRowNum()).getLastCellNum();
            for (int i = 0; i < lastCellNum; i++) {
                autoSizeColumn(sheet, i);
            }
        }
    }

    public static void autoSizeColumn(Sheet sheet, int column) {
        int columnWidth = sheet.getColumnWidth(column) * 17 / 10;
        if (columnWidth < 255 * 255) {
            //65280 excel列宽固定需扩容
            sheet.autoSizeColumn(column);
            sheet.setColumnWidth(columnWidth, columnWidth < 3000 ? 3000 : columnWidth);
        } else {
            sheet.setColumnWidth(columnWidth, 6000);
        }
    }

    public static HSSFWorkbook getHSSFWorkbook(String sheetName, String[] title, String[][] value, HSSFWorkbook web) {
        if (web == null) {
            web = new HSSFWorkbook();
        }
        HSSFSheet sheet = web.getSheet(sheetName);

        HSSFRow row = sheet.createRow(0);

        HSSFCellStyle cellStyle = web.createCellStyle();
        cellStyle.setAlignment(cellStyle.getAlignment());

        HSSFCell cell = null;
        for (int i = 0; i < title.length; i++) {
            cell = row.createCell(i);
            cell.setCellValue(title[i]);
            cell.setCellStyle(cellStyle);
        }
        //创建内容
        for (int i = 0; i < value.length; i++) {
            row = sheet.getRow(i + 1);
            for (int j = 0; j < value[i].length; j++) {
                row.createCell(j).setCellValue(value[i][j]);
            }
        }
        return web;
    }
}
